/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- BBS: www.STCAIMCU.com  -----------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
/*---------------------------------------------------------------------*/

/*************  功能说明    **************
本例程基于STC8H8K64U为主控芯片的实验箱9进行编写测试，STC8G、STC8H系列芯片可通用参考.
通过串口2(P4.6 P4.7)对STC内部自带的EEPROM(FLASH)进行读写测试。
对FLASH做扇区擦除、写入、读出的操作，命令指定地址。
默认波特率:  115200,8,N,1. 
默认主时钟:  22.1184MHz.
串口命令设置: (命令字母不区分大小写)
    W 0x0040 1234567890  --> 对0x0040地址写入字符1234567890.
    R 0x0040 10          --> 对0x0040地址读出10个字节数据. 

注意：下载时，下载界面"硬件选项"中设置用户EEPROM大小，
并确保串口命令中的地址在EEPROM设置的大小范围之内。
******************************************/

#include <STC8G_H_GPIO.h>
#include <STC8G_H_UART.h>
#include <STC8G_H_Timer.h>
#include <STC8G_H_Delay.h>
#include <STC8G_H_EEPROM.h>

#define Tmp_Length (COM_RX2_Lenth-9)      //读写EEPROM缓冲长度
u8  __xdata   tmp[Tmp_Length];        //EEPROM操作缓冲

INTERRUPT(UART2_int, UART2_VECTOR);
void GPIO_Init();
void UART2_Init();
u16 ParseAddress(void);
u8 CheckData(u8 dat);
u8 GetDataLength(void);

//========================================================================
// 函数: void main(void)
// 描述: 主函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注: 
//========================================================================
void main(void)
{
    u8 i,j;
    u16 addr;
    u8 status;  // 用于记录通过串口接收到的命令是否正确
    P_SW2 |= 0x80;  //扩展寄存器(XFR)访问使能

    GPIO_Init();
    UART2_Init();

    EA = 1; //允许总中断

    PrintString2("STC8H8K64U UART2 Test Programme!\r\n");  //UART1发送一个字符串

    while (1)
    {
        delay_ms(1);
        if(COM2.RX_TimeOut > 0) {   //默认值是0 当接受中断时 设置为5，因此当这个值>0表示收到数据
            if(--COM2.RX_TimeOut == 0) {  //当知道收到数据后需要判断是不是接收完毕，如果这个值不是0说明5秒内有收到数据， 只有当这个值不是0 说明5秒内没有新数据，可以开始处理收到的数据。
                if(COM2.RX_Cnt > 0) {
                    for (i = 0; i < COM2.RX_Cnt; i++)
                    {
                        TX2_write2buff(RX2_Buffer[i]);  // 把接收到的数据原样返回
                    }

                    status = 0xff; 
                    // 开始解析并且执行命令
                    if(COM2.RX_Cnt >= 10 && (RX2_Buffer[1] == ' ') && (RX2_Buffer[8] == ' ')) {
                        // 将命令和地址转换成大写
                        for(i=0; i<8; i++)
                        {
                            if((RX2_Buffer[i] >= 'a') && (RX2_Buffer[i] <= 'z')) {
                                RX2_Buffer[i] = RX2_Buffer[i] - 'a' + 'A';  //小写转大写
                            }
                        }
                        addr = ParseAddress();  // 从接收到的数据中解析出需要操作的地址
                        if(addr < 63488) {
                            // 地址是合法的，进一步判断是写操作还是读操作
                            if(RX2_Buffer[0] == 'W') {
                                // 写操作
                                j = COM2.RX_Cnt - 9; // 存储串口接收到的需要写入eeprom的数据长度；
                                if(j > Tmp_Length) {
                                    j = Tmp_Length;
                                }
                                EEPROM_SectorErase(addr);  // 调用库函数删除扇区
                                EEPROM_write_n(addr, &RX2_Buffer[9], j);
                                PrintString2("已写入！\r\n");
                                // if(i == 0) {
                                //     PrintString2("已写入");
                                //     if(j >= 100) {
                                //         TX2_write2buff(j/100+'0');   
                                //         j = j % 100;
                                //     }
                                //     if(j >= 10) {
                                //         TX2_write2buff(j/10+'0');    
                                //         j = j % 10;
                                //     }
                                //     TX2_write2buff(j%10+'0');
                                //     PrintString2("字节！\r\n");
                                // } else {
                                //     PrintString2("写入错误！\r\n");
                                // }
                                status = 0;  // 命令是正确的
                            } else if (RX2_Buffer[0] == 'R') {
                                // 读操作
                                j = GetDataLength();   // 获取读命令后边跟着的数量
                                if(j > Tmp_Length) {
                                    j = Tmp_Length; //越界检测
                                }
                                if(j > 0)
                                {
                                    PrintString2("读出");
                                    TX2_write2buff(j/10+'0');
                                    TX2_write2buff(j%10+'0');
                                    PrintString2("个字节内容如下:\r\n");
                                    EEPROM_read_n(addr,tmp,j);
                                    for(i=0; i<j; i++) {
                                        TX2_write2buff(tmp[i]);
                                    }
                                    TX2_write2buff(0x0d);
                                    TX2_write2buff(0x0a);
                                    status = 0; //命令正确
                                }

                            }
                        } 
                    

                    }

                    if(status != 0) {
                        PrintString2("命令错误！\r\n");
                    }
                    COM2.RX_Cnt = 0;
                }
                
            }
        }
    }
}

//========================================================================
// 函数: void GPIO_Init (void)
// 描述: 端口初始化函数.
// 参数: none.
// 返回: none.
//========================================================================
void GPIO_Init()
{
    GPIO_InitTypeDef initTypeDef;
    initTypeDef.Mode = GPIO_OUT_OD;
    initTypeDef.Pin = GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Inilize(GPIO_P0, &initTypeDef); // 设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
    GPIO_Inilize(GPIO_P1, &initTypeDef); // 设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Inilize(GPIO_P2, &initTypeDef); // 设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
    GPIO_Inilize(GPIO_P3, &initTypeDef); // 设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Inilize(GPIO_P4, &initTypeDef); // 设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_Inilize(GPIO_P5, &initTypeDef); // 设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Pin = GPIO_Pin_All;
    GPIO_Inilize(GPIO_P6, &initTypeDef); // 设置为漏极开路(实验箱加了上拉电阻到3.3V)
    initTypeDef.Mode = GPIO_PullUp;
    initTypeDef.Pin = GPIO_Pin_All;
    GPIO_Inilize(GPIO_P7, &initTypeDef); // 设置为准双向口
    initTypeDef.Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Inilize(GPIO_P4, &initTypeDef); // 设置为准双向口
}

//========================================================================
// 函数: void UART2_Init (void)
// 描述: 串口2初始化函数.
// 参数: none.
// 返回: none.
//========================================================================
void UART2_Init(){
    COMx_InitDefine		COMx_InitStructure;					//结构定义
	COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;		//模式,       UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
	COMx_InitStructure.UART_BRT_Use   = BRT_Timer2;			//选择波特率发生器,   BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
	COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200
	COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLE
	COMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLE
	COMx_InitStructure.UART_Interrupt = ENABLE;				//中断允许,   ENABLE或DISABLE
	COMx_InitStructure.UART_Priority  = Priority_0;			//指定中断优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	COMx_InitStructure.UART_P_SW      = UART2_SW_P46_P47;	//切换端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
	UART_Configuration(UART2, &COMx_InitStructure);		    //初始化串口1 UART1,UART2,UART3,UART4
}

//========================================================================
// 函数: u8 CheckData(u8 dat)
// 描述: 将字符"0~9,A~F或a~f"转成十六进制.
// 参数: dat: 要检测的字符.
// 返回: 0x00~0x0F为正确. 0xFF为错误.
// 版本: V1.0, 2012-10-22
//========================================================================
u8 CheckData(u8 dat)
{
    if((dat >= '0') && (dat <= '9'))        return (dat-'0');
    if((dat >= 'A') && (dat <= 'F'))        return (dat-'A'+10);
    return 0xff;
}

//========================================================================
// 函数: u16    ParseAddress(void)
// 描述: 计算各种输入方式的地址.
// 参数: 无.
// 返回: 16位EEPROM地址.
// 版本: V1.0, 2013-6-6
//========================================================================
u16 ParseAddress(void)
{
    u16 address;
    u8  i,j;
    
    address = 0;
    if((RX2_Buffer[2] == '0') && (RX2_Buffer[3] == 'X'))
    {
        for(i=4; i<8; i++)
        {
            j = CheckData(RX2_Buffer[i]);
            if(j >= 0x10) {
                return 65535;   //error
            }
            address = (address << 4) + j;
        }
        return (address);
    }
    return  65535;  //error
}

u8 GetDataLength(void)
{
    u8  i;
    u8  length;
    
    length = 0;
    for(i=9; i<COM2.RX_Cnt; i++)
    {
        if(CheckData(RX2_Buffer[i]) >= 10) {
            break;
        }
        length = length * 10 + CheckData(RX2_Buffer[i]);
    }
    return (length);
}

//========================================================================
// 函数: void UART2_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注: 
//========================================================================
INTERRUPT(UART2_int, UART2_VECTOR)
{
    if(RI2)
    {
        CLR_RI2();
        if(COM2.B_RX_OK == 0)
        {
            if(COM2.RX_Cnt >= COM_RX2_Lenth) {
                COM2.RX_Cnt = 0;
            }
            RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
            COM2.RX_TimeOut = TimeOutSet2;
        }
    }

    if(TI2)
    {
        CLR_TI2();
        if(COM2.TX_read != COM2.TX_write) 
        {
            S2BUF = TX2_Buffer[COM2.TX_read];
            if(++COM2.TX_read >= COM_TX2_Lenth)
            {
                COM2.TX_read = 0;
            }
        } else {
            COM2.B_TX_busy = 0;		//标志忙
        }

    }
}

